package com.jsy.mini12306.ticketsales.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jsy.mini12306.TicketOrderService;
import com.jsy.mini12306.common.entity.SeatType;
import com.jsy.mini12306.common.entity.Ticket;
import com.jsy.mini12306.common.entity.TicketOrder;
import com.jsy.mini12306.common.entity.TicketOrderIterm;
import com.jsy.mini12306.ticketsales.bo.DrivingPlan;
import com.jsy.mini12306.ticketsales.entity.SeatLocation;
import com.jsy.mini12306.ticketsales.exception.TicketSaleCoreException;
import com.jsy.mini12306.ticketsales.mapper.TicketMapper;
import com.jsy.mini12306.ticketsales.service.RemainingSeatsService;
import com.jsy.mini12306.ticketsales.service.TicketService;
import com.jsy.mini12306.ticketsales.vo.TicketOrderItermVO;
import com.jsy.mini12306.ticketsales.vo.TicketOrderVO;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 票价(Ticket)表服务实现类
 *
 * @author: SongyangJi
 * @since: 2021-09-03 19:32:33
 * @description:
 */

@Slf4j
@Service("ticketService")
public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> implements TicketService {

    @Resource
    TicketMapper ticketMapper;

    @Resource
    RemainingSeatsService remainingSeatsService;


    // RPC 服务调用
    @Reference
    TicketOrderService ticketOrderService;

    @Override
    public Map<SeatType, Float> queryTicketPriceByDrivingPlan(DrivingPlan drivingPlan) {
        int trainId = drivingPlan.getTrain().getTrainId();
        Integer startStationId = drivingPlan.getDepartStation().getStationId();
        Integer endStationId = drivingPlan.getArrivalStation().getStationId();

        List<Ticket> tickets = ticketMapper.selectList(new QueryWrapper<Ticket>()
                .eq("train_id", trainId)
                .eq("start_station_id", startStationId)
                .eq("end_station_id", endStationId)
        );
        Map<SeatType, Float> seatPrices = new HashMap<>();
        // 设置价格
        for (Ticket ticket : tickets) {
            seatPrices.put(ticket.getSeatType(), ticket.getPrice());
        }
        return seatPrices;
    }


    @Transactional
    @Override
    public boolean processTicketOrder(TicketOrderVO ticketOrderVO) throws TicketSaleCoreException {
        DrivingPlan drivingPlan = ticketOrderVO.generateDrivingPlan();
        List<TicketOrderItermVO> orderIterms = ticketOrderVO.getOrderIterms();
        // 分别处理每张票
        List<TicketOrderIterm> ticketOrderIterms = new ArrayList<>();
        for (TicketOrderItermVO itermVO : orderIterms) {
            SeatType seatType = itermVO.getSeatType();
            SeatLocation seatLocation = remainingSeatsService.buyTicketAndOccupySeat(drivingPlan, seatType);

            // 数据库无任何数据发生变化，告诉前端票没抢到即可
            if (seatLocation == null) {
                return false;
            }
            // 走到这一步数据库的座位图已经发生了变化，下面开始生成订单、入库，要注意事务的一致性
            TicketOrderIterm orderIterm = TicketOrderIterm.builder()
                    .passengerId(itermVO.getPassenger().getPassengerId())
                    .ticketType(itermVO.getPassenger().getType().getType())
                    .price(itermVO.getPrice())
                    .seatType(itermVO.getSeatType())
                    .bin(seatLocation.getBin())
                    .seat(seatLocation.getSeat()).build();
            ticketOrderIterms.add(orderIterm);
        }
        TicketOrder ticketOrder = TicketOrder.builder()
                .buyerId(ticketOrderVO.getBuyer().getPassengerId())
                .dateTime(LocalDateTime.now())
                .trainId(ticketOrderVO.getTrain().getTrainId())
                .departDate(ticketOrderVO.getDepartDate())
                .startStationId(ticketOrderVO.getDepartStation().getStationId())
                .endStationId(ticketOrderVO.getArrivalStation().getStationId())
                .trainName(ticketOrderVO.getTrain().getTrainName())
                .ticketOrderIterms(ticketOrderIterms).build();
        // 入库
        ticketOrderService.saveTicketOrder(ticketOrder);
        return true;
    }
}
